﻿Public Class frmFinancialSetupAcct
    '窗体
    Private m_state As Integer '编辑状态 0- 浏览1- 新增 2-修改

    Private m_dirty As Boolean '数据被修改
    Private m_saving As Boolean '数据正在存储
    Private m_canEdit As Boolean '当前是否可以编辑，即是否选择了某个科目
    Private m_broker As ClsBroker = New ClsBroker() '新增或修改后发布广播事件


    '定义委托，将取得的数据加载到树上
    Private Delegate Sub AcctClassToTree(ByVal cls As ClsTAccount)
    Private m_loadNode As AcctClassToTree = New AcctClassToTree(AddressOf LoadOneAcctToTree)
    '定义一个委托，用来在主窗体上显示 当前的工作进程信息
    Private Delegate Sub SetNotifyInfo(ByVal s As String)
    Private m_ShowNotify As SetNotifyInfo = New SetNotifyInfo(AddressOf sysFrmMdiMain.SetNotifyText)

    '当前正在处理的科目对象
    Private m_curAcctCls As ClsTAccount

    '当前正在处理的树节点对象
    Private m_curNode As TreeNode

    '当前窗体正在使用的科目对象集合
    Private m_acctList As List(Of ClsTAccount)
    '窗体使用的科目类型数据源
    Private m_acctGroupList As List(Of ClsIndustryAccountGroup)
    '借贷方向数据源
    Private m_balanceDirectionList As List(Of String)
    'AB账设置数据源
    Private m_abSetList As List(Of String)
    '结转方向数据源
    Private m_acctTransitList As List(Of String)

    Private Sub frmFinancialSetupAcct_Load(sender As Object, e As EventArgs) Handles MyBase.Load
        '初始化窗体
        '注册委托，订阅事件
        AddHandler ClsBroker.OnCustomCtrolContentChange, AddressOf MyTextChanged

        '修改状态
        m_state = 0
        m_dirty = False
        m_saving = False
        m_canEdit = False

        '检查控件状态
        CheckControlState()

        '载入数据（异步）
        LoadData()
    End Sub

    Private Sub MyTextChanged(ByVal sender As Object, ByVal e As CustomControlChangeNotifyEventArg)
        If Not e.FormWehere.Equals(Me.Name) Then
            Return
        End If
        m_dirty = True

        Me.btnSave.Enabled = True
    End Sub

    ''' <summary>
    ''' 检查当下窗体的控件状态
    ''' </summary>
    Private Sub CheckControlState()

        CheckButtonState()

        CheckEditControlState()

    End Sub

    ''' <summary>
    ''' 检查当前按钮状态
    ''' </summary>
    Private Sub CheckButtonState()
        Select Case m_state
            Case 0 '浏览
                Me.btnAddSame.Enabled = m_canEdit
                Me.btnAddNext.Enabled = m_canEdit
                Me.btnModify.Enabled = m_canEdit
                Me.btnDelete.Enabled = m_canEdit
                Me.btnCancel.Text = "取消&U"
                Me.btnCancel.Enabled = False
                Me.btnSave.Enabled = False
                Me.btnClose.Enabled = True
                Me.btnInput.Enabled = True
            Case 1 '新增
                Me.btnAddSame.Enabled = False
                Me.btnAddNext.Enabled = False
                Me.btnModify.Enabled = False
                Me.btnDelete.Enabled = False
                Me.btnCancel.Enabled = True
                Me.btnSave.Enabled = True
                Me.btnClose.Enabled = True
                Me.btnInput.Enabled = False
            Case 2 '修改
                Me.btnAddSame.Enabled = False
                Me.btnAddNext.Enabled = False
                Me.btnModify.Enabled = False
                Me.btnDelete.Enabled = False
                Me.btnCancel.Enabled = True
                Me.btnSave.Enabled = True
                Me.btnClose.Enabled = True
                Me.btnInput.Enabled = True
        End Select
    End Sub

    ''' <summary>
    ''' 检查窗体上可编辑控件状态
    ''' </summary>
    Private Sub CheckEditControlState()
        Select Case m_state
            Case 0 '浏览
                '基础信息区
                Me.txtAcctCode.ReadOnly = True
                Me.cmbAcctType.Enabled = False
                Me.txtAcctName.ReadOnly = True
                Me.cmbBalanceDirection.Enabled = False
                Me.chkIfLastLevel.Enabled = False
                Me.txtYearMoney.ReadOnly = True
                Me.cmbAbSet.Enabled = False
                '外币核算区
                Me.txtCurrencyCode.ReadOnly = True
                Me.chkIfAdjust.Enabled = False
                Me.txtYearCurrency.ReadOnly = True
                '数量核算区
                Me.chkIfQuantity.Enabled = False
                Me.txtQuantityUnit.ReadOnly = True
                Me.txtYearQuantity.ReadOnly = True
                '其他核算区
                Me.chkIfProject.Enabled = False
                Me.chkIfCustomer.Enabled = False
                Me.chkIfDepartment.Enabled = False
                Me.chkIfEmployee.Enabled = False
                '损益结转区
                Me.cmbTransit.Enabled = False
                Me.txtTransitAcctCode.ReadOnly = True
            Case 1 '新增
                '基础信息区
                Me.txtAcctCode.ReadOnly = False
                Me.cmbAcctType.Enabled = True
                Me.txtAcctName.ReadOnly = False
                Me.cmbBalanceDirection.Enabled = True
                Me.chkIfLastLevel.Enabled = True
                Me.txtYearMoney.ReadOnly = False
                Me.cmbAbSet.Enabled = True
                '外币核算区
                Me.txtCurrencyCode.ReadOnly = False
                Me.chkIfAdjust.Enabled = True
                Me.txtYearCurrency.ReadOnly = False
                '数量核算区
                Me.chkIfQuantity.Enabled = True
                Me.txtQuantityUnit.ReadOnly = False
                Me.txtYearQuantity.ReadOnly = False
                '其他核算区
                Me.chkIfProject.Enabled = True
                Me.chkIfCustomer.Enabled = True
                Me.chkIfDepartment.Enabled = True
                Me.chkIfEmployee.Enabled = True
                '损益结转区
                Me.cmbTransit.Enabled = True
                Me.txtTransitAcctCode.ReadOnly = False
            Case 2 '修改
                '基础信息区
                Me.txtAcctCode.ReadOnly = True
                Me.cmbAcctType.Enabled = True
                Me.txtAcctName.ReadOnly = False
                Me.cmbBalanceDirection.Enabled = True
                Me.chkIfLastLevel.Enabled = True
                Me.txtYearMoney.ReadOnly = False
                Me.cmbAbSet.Enabled = True
                '外币核算区
                Me.txtCurrencyCode.ReadOnly = False
                Me.chkIfAdjust.Enabled = True
                Me.txtYearCurrency.ReadOnly = False
                '数量核算区
                Me.chkIfQuantity.Enabled = True
                Me.txtQuantityUnit.ReadOnly = False
                Me.txtYearQuantity.ReadOnly = False
                '其他核算区
                Me.chkIfProject.Enabled = True
                Me.chkIfCustomer.Enabled = True
                Me.chkIfDepartment.Enabled = True
                Me.chkIfEmployee.Enabled = True
                '损益结转区
                Me.cmbTransit.Enabled = True
                Me.txtTransitAcctCode.ReadOnly = False
        End Select
    End Sub

    ''' <summary>
    ''' 加载当前窗体的主要数据：科目集合,并加载到树中
    ''' </summary>
    Private Sub LoadData()
        '加载控件数据源
        LoadDataSource()
        '加载全部科目
        LoadAcctData()
    End Sub

    Private Sub LoadDataSource()
        '载入各个comboBox的数据源
        '1、科目类型数据源
        sysFrmMdiMain.SetNotifyText("正在加载数据源...")
        'm_acctGroupList = New List(Of ClsIndustryAccountGroup)
        Dim tmpAcctGroupDb As ClsIndustryAccountGroupDbAccess = New ClsIndustryAccountGroupDbAccess(sysAppInfoConnectionString)
        m_acctGroupList = tmpAcctGroupDb.GetGroupsByTypeId(sysCurrentLedgerSetting.IndustryTypeId)
        With Me.cmbAcctType
            .DataSource = m_acctGroupList
            .ValueMember = "AcctGroupName"
            .DisplayMember = "AcctGroupName"
        End With

        '2、借贷方向数据源
        m_balanceDirectionList = New List(Of String)
        m_balanceDirectionList.Add("借方")
        m_balanceDirectionList.Add("贷方")
        Me.cmbBalanceDirection.DataSource = m_balanceDirectionList
        'Me.cmbBalanceDirection.Items.AddRange(m_balanceDirectionList.ToArray())

        '3、AB账设置数据源
        m_abSetList = New List(Of String)
        m_abSetList.Add("通用")
        m_abSetList.Add("A账专用")
        m_abSetList.Add("B账专用")
        Me.cmbAbSet.Items.AddRange(m_abSetList.ToArray())

        '4、结转方式数据源
        m_acctTransitList = New List(Of String)
        m_acctTransitList.Add("借方金额结转")
        m_acctTransitList.Add("贷方金额结转")
        Me.cmbTransit.Items.AddRange(m_acctTransitList.ToArray())

        '5、加载树一级节点
        For Each tmpGroup As ClsIndustryAccountGroup In m_acctGroupList
            Dim tmpNode As TreeNode = New TreeNode()
            tmpNode.Name = tmpGroup.AcctGroupName
            tmpNode.Text = tmpGroup.AcctGroupName
            Me.treeAcct.Nodes.Add(tmpNode)
        Next

        '6、树控件取得当前焦点
        Me.treeAcct.Select()

    End Sub

    Private Sub LoadAcctData()
        '载入科目集合数据
        Dim t As Threading.Thread = New Threading.Thread(AddressOf LoadAcctFromDb)
        t.Start()

    End Sub

    ''' <summary>
    ''' 从表中加载数据
    ''' </summary>
    Private Sub LoadAcctFromDb()
        '通知主窗体，现在背景工作
        sysFrmMdiMain.Invoke(m_ShowNotify, New Object() {"正在加载科目信息"})

        '1、取出所有科目，循环加载
        Dim tmpAcctDb As ClsTAccountDbAccess = New ClsTAccountDbAccess(sysUserDataConnectionString)

        m_acctList = tmpAcctDb.GetAllRecords(Of ClsTAccount)("AccountCode", True)
        '2、将科目加载到树控件中
        For Each tmpAcct As ClsTAccount In m_acctList
            Me.Invoke(m_loadNode, New Object() {tmpAcct})
        Next
        sysFrmMdiMain.Invoke(m_ShowNotify, New Object() {"就绪"})
    End Sub

    Private Sub LoadOneAcctToTree(ByVal tmpCls As ClsTAccount)
        '将科目对象加载到树控件中
        '如果是一级科目，加载到科目分组中
        If tmpCls Is Nothing Then
            Return
        End If

        Dim tmpNode As TreeNode = New TreeNode()
        tmpNode.Name = tmpCls.AccountCode
        tmpNode.Text = tmpCls.AccountCode & " - " & tmpCls.AccountName
        tmpNode.Tag = tmpCls

        If tmpCls.Level = 1 Then
            Me.treeAcct.Nodes(tmpCls.AccountType).Nodes.Add(tmpNode)
        Else
            '
            Dim tmpParentNode As TreeNode = GetNodeByName(tmpCls.PrevLevelCode, tmpCls.AccountType)
            tmpParentNode.Nodes.Add(tmpNode)

        End If
    End Sub

    ''' <summary>
    ''' 根据科目编号和科目组别（资产、负债等）返回节点
    ''' </summary>
    ''' <param name="n">查找的科目编码</param>
    ''' <param name="t">科目的组别名称：资产、负债等</param>
    ''' <returns></returns>
    Private Function GetNodeByName(ByVal n As String, ByVal t As String) As TreeNode
        '搜索直接一级
        For Each tmpN As TreeNode In Me.treeAcct.Nodes(t).Nodes
            If tmpN.Name.Equals(n) Then
                Return tmpN
            End If

            If tmpN.Nodes.Count > 0 Then
                Dim tmpNode As TreeNode = GetNextNode(tmpN, n)
                If tmpNode IsNot Nothing Then
                    Return tmpNode
                End If
            End If
        Next

        'For Each tmpN As TreeNode In Me.treeAcct.Nodes
        '    If tmpN.Name.Equals(n) Then
        '        Return tmpN
        '    End If

        '    If tmpN.Nodes.Count > 0 Then
        '        Dim tmpNode As TreeNode = GetNextNode(tmpN, n)
        '        If tmpNode IsNot Nothing Then
        '            Return tmpNode
        '        End If
        '    End If
        'Next

        Return Nothing

    End Function

    Private Function GetNextNode(ByVal node As TreeNode, ByVal n As String) As TreeNode
        '递归一条二级节点
        For Each tmpN As TreeNode In node.Nodes
            If tmpN.Name.Equals(n) Then
                Return tmpN
            End If

            If tmpN.Nodes.Count > 0 Then
                Dim tmpNode As TreeNode = GetNextNode(tmpN, n)
                If tmpNode IsNot Nothing Then
                    Return tmpNode
                End If
            End If
        Next

        Return Nothing

    End Function

    Private Sub btnClose_Click(sender As Object, e As EventArgs) Handles btnClose.Click
        '1、判断是否有需要保存的数据
        '2、关闭
        Me.Close()
    End Sub

    Private Sub treeAcct_AfterSelect(sender As Object, e As TreeViewEventArgs) Handles treeAcct.AfterSelect
        '获取当前操作节点
        m_curNode = e.Node

        '选中某节点
        If m_curNode Is Nothing Then
            Return
        End If

        If m_curNode.Tag Is Nothing Then
            '一级节点，是科目组，不做处理
            '为避免使用组节点进行编辑处理，置空当前操作的科目对象
            m_curAcctCls = Nothing
            '清空控件内容
            ClearControlContent()
            Return
        End If

        Dim tmpAcctCls As ClsTAccount = TryCast(m_curNode.Tag, ClsTAccount)
        If tmpAcctCls Is Nothing Then
            Return
        End If

        '当前节点对象赋值给窗体当前对象
        m_curAcctCls = tmpAcctCls

        '类对象入控件
        ClassToControl()
        '当前可以编辑
        m_canEdit = True
        CheckButtonState()
    End Sub

    ''' <summary>
    ''' 当选择科目组时，清空编辑区控件内容
    ''' </summary>
    Private Sub ClearControlContent()
        Me.txtAcctCode.Text = ""
        Me.txtAcctName.Text = ""

        Me.chkIfLastLevel.Checked = False
        Me.txtYearMoney.Text = ""

        Me.cmbAcctType.SelectedIndex = -1

        Me.cmbBalanceDirection.SelectedIndex = -1
        '外币核算区
        Me.txtCurrencyCode.Text = ""
        Me.chkIfAdjust.Checked = False
        Me.txtYearCurrency.Text = ""
        '数量核算区
        Me.chkIfQuantity.Checked = False
        Me.txtQuantityUnit.Text = ""
        Me.txtYearQuantity.Text = ""
        '其他核算区
        Me.chkIfProject.Checked = False
        Me.chkIfCustomer.Checked = False
        Me.chkIfDepartment.Checked = False
        Me.chkIfEmployee.Checked = False
        '损益结转区
        Me.cmbTransit.SelectedIndex = -1

        Me.txtTransitAcctCode.Text = ""
        '隐藏区
        Me.txtFullName.Text = ""
        Me.txtPrevLevelCode.Text = ""
        Me.txtShortName.Text = ""
        Me.txtLevel.Text = ""

    End Sub


    ''' <summary>
    ''' 取出当前科目组在集合中的索引
    ''' </summary>
    ''' <param name="s">指定的科目组名称</param>
    ''' <returns>在集合中的索引，没找到返回-1</returns>
    Private Function GetIndexOfAcctType(ByVal s As String) As Integer
        For Each tmpG As ClsIndustryAccountGroup In m_acctGroupList
            If tmpG.AcctGroupName.Equals(s) Then
                Return m_acctGroupList.IndexOf(tmpG)
            End If
        Next

        Return -1

    End Function

    ''' <summary>
    ''' 返回当前借贷方向在集合中的索引
    ''' </summary>
    ''' <param name="s">指定的借贷方向</param>
    ''' <returns>集合中索引，没找到返回-1</returns>
    Private Function GetIndexOfBalanceDirection(ByVal s As String) As Integer
        For Each tmpS As String In m_balanceDirectionList
            If tmpS.Equals(s) Then
                Return m_balanceDirectionList.IndexOf(tmpS)
            End If
        Next

        Return -1

    End Function

    Private Function GetIndexOfTransit(ByVal s As String) As Integer
        For Each tmpS As String In m_acctTransitList
            If tmpS.Equals(s) Then
                Return m_acctTransitList.IndexOf(tmpS)
            End If
        Next

        Return -1
    End Function

    ''' <summary>
    ''' 返回当前节点父节点文本
    ''' </summary>
    ''' <param name="node"></param>
    ''' <returns></returns>
    Private Function GetCurNodeParentName(ByVal node As TreeNode) As String
        Dim tmpName As String = node.Text.Substring(node.Text.IndexOf("-") + 1)

        If node.Parent IsNot Nothing AndAlso node.Parent.Tag IsNot Nothing Then
            tmpName = GetCurNodeParentName(node.Parent) & tmpName
        End If

        Return tmpName

    End Function

    Private Sub ControlToClass()
        '判断是否为新增
        If m_curAcctCls Is Nothing OrElse m_state = 1 Then
            m_curAcctCls = New ClsTAccount()
        End If

        With m_curAcctCls
            '只有新增才可以修改以下三个成员内容
            If m_state = 1 Then
                .AccountCode = Me.txtAcctCode.Text.Trim
                .PrevLevelCode = Me.txtPrevLevelCode.Text.Trim()
                .Level = Integer.Parse(Me.txtLevel.Text)
                '处理科目全名
                If .Level = 1 Then
                    .FullName = Me.txtAcctName.Text.Trim()
                Else
                    If .Level = CType(m_curNode.Tag, ClsTAccount).Level Then
                        '新增同级
                        .FullName = GetCurNodeParentName(m_curNode.Parent) & "/" & Me.txtAcctName.Text.Trim()
                    Else
                        '新增下级
                        .FullName = GetCurNodeParentName(m_curNode) & "/" & Me.txtAcctName.Text.Trim()
                    End If
                End If
            Else
                '修改，则修改科目命名
                If .Level = 1 Then
                    .FullName = Me.txtAcctName.Text.Trim()
                Else
                    If .FullName.LastIndexOf("/") = -1 Then
                        '说明没有全名
                        .FullName = GetCurNodeParentName(m_curNode.Parent) & "/" & Me.txtAcctName.Text.Trim()
                    Else
                        '有全名
                        .FullName = .FullName.Substring(0, .FullName.LastIndexOf("/") + 1) & Me.txtAcctName.Text.Trim()
                    End If
                End If
            End If

            .AccountName = Me.txtAcctName.Text.Trim
            .ShortName = Me.txtShortName.Text.Trim()
            .IfLastLevel = Me.chkIfLastLevel.Checked
            .AccountType = Me.cmbAcctType.SelectedValue
            .YearMoney = Decimal.Parse(Me.txtYearMoney.Text.Trim())
            .BalanceDirection = Me.cmbBalanceDirection.SelectedValue
            .YearCurrency = Decimal.Parse(Me.txtYearCurrency.Text.Trim())
            .CurrencyCode = Me.txtCurrencyCode.Text.Trim
            .IfRateAdjust = Me.chkIfAdjust.Checked
            .IfQuantity = Me.chkIfQuantity.Checked
            .QuantityUnit = Me.txtQuantityUnit.Text.Trim
            .YearQuantity = Single.Parse(Me.txtYearQuantity.Text.Trim())
            .IfProject = Me.chkIfProject.Checked
            .IfCustomer = Me.chkIfCustomer.Checked
            .IfDepartment = Me.chkIfDepartment.Checked
            .IfEmployee = Me.chkIfEmployee.Checked
            .MonthTransit = Me.cmbTransit.SelectedValue
            .MonthTransitAcctCode = Me.txtTransitAcctCode.Text.Trim()
            .AbSet = 0
        End With
    End Sub

    Private Sub ClassToControl()
        If m_curAcctCls Is Nothing Then
            Return
        End If
        With m_curAcctCls
            '基础信息区
            Me.txtAcctCode.Text = .AccountCode
            Me.txtAcctName.Text = .AccountName

            Me.chkIfLastLevel.Checked = .IfLastLevel
            Me.txtYearMoney.Text = .YearMoney

            Me.cmbAcctType.SelectedIndex = GetIndexOfAcctType(.AccountType)

            Me.cmbBalanceDirection.SelectedIndex = GetIndexOfBalanceDirection(.BalanceDirection)
            '外币核算区
            Me.txtCurrencyCode.Text = .CurrencyCode
            Me.chkIfAdjust.Checked = .IfRateAdjust
            Me.txtYearCurrency.Text = .YearCurrency
            '数量核算区
            Me.chkIfQuantity.Checked = .IfQuantity
            Me.txtQuantityUnit.Text = .QuantityUnit
            Me.txtYearQuantity.Text = .YearQuantity
            '其他核算区
            Me.chkIfProject.Checked = .IfProject
            Me.chkIfCustomer.Checked = .IfCustomer
            Me.chkIfDepartment.Checked = .IfDepartment
            Me.chkIfEmployee.Checked = .IfEmployee
            '损益结转区
            Me.cmbTransit.SelectedIndex = GetIndexOfTransit(.MonthTransit)

            Me.txtTransitAcctCode.Text = .MonthTransitAcctCode
            '隐藏区
            Me.txtFullName.Text = .FullName
            Me.txtPrevLevelCode.Text = .PrevLevelCode
            Me.txtShortName.Text = .ShortName
            Me.txtLevel.Text = .Level
        End With
    End Sub

    Private Sub btnAddSame_Click(sender As Object, e As EventArgs) Handles btnAddSame.Click
        '增加同级科目
        '判断当下是否可以新增
        If m_curAcctCls Is Nothing Then
            MessageBox.Show("请先选择一个上级科目，不能选择科目组（如资产）。", "新增同级科目")
            Return
        End If
        '修改状态
        m_state = 1 '新增
        '修改取消按钮文字
        Me.btnCancel.Text = "取消新增同级&U"

        '锁定树控件
        Me.treeAcct.Enabled = False

        '检查当前控件状态
        CheckControlState()

        '填写必要的值 
        Dim tmpCode As String = GetNewSameAcctCode(m_curNode)
        Me.txtAcctCode.Text = IIf(tmpCode Is Nothing, "无法创建同级科目", tmpCode)
        Me.txtAcctName.Text = ""
        Me.txtPrevLevelCode.Text = m_curAcctCls.PrevLevelCode
        Me.txtShortName.Text = ""
        Me.txtFullName.Text = "" '
        Me.txtLevel.Text = m_curAcctCls.Level
    End Sub

    ''' <summary>
    ''' 返回当前选择科目同级科目的下一个科目作为新增科目
    ''' </summary>
    ''' <param name="node"></param>
    ''' <returns></returns>
    Private Function GetNewSameAcctCode(ByVal node As TreeNode) As String
        If node Is Nothing Then
            Return Nothing
        End If
        '在当前节点的父节点中查找合适的节点（最后一个节点）
        Dim lastIndex As Integer = node.Parent.Nodes.Count - 1
        Dim lastAcctCls As ClsTAccount = TryCast(node.Parent.Nodes(lastIndex).Tag, ClsTAccount)
        Dim lastCode As String = IIf(lastAcctCls Is Nothing, Nothing, lastAcctCls.AccountCode)
        Dim tmpNumStr As String
        If lastCode.Length <= 3 Then
            tmpNumStr = lastCode
        Else
            tmpNumStr = lastCode.Substring(lastCode.Length - 3, 3)
        End If

        Dim retCode As String = IIf(lastCode Is Nothing, Nothing, lastCode.Substring(0, lastCode.Length - 3) & （Integer.Parse(tmpNumStr) + 1).ToString("D3"))

        Return retCode
    End Function

    Private Function GetNewNextAcctCode(ByVal node As TreeNode) As String
        If node Is Nothing Then
            Return Nothing
        End If
        '当前节点中所有子节点中最后一个节点

        Dim lastIndex As Integer
        Dim lastAcctCls As ClsTAccount
        Dim lastCode As String
        Dim retCode As String
        If node.Nodes.Count > 0 Then
            lastIndex = node.Nodes.Count - 1
        Else
            lastAcctCls = TryCast(node.Tag, ClsTAccount)
            lastIndex = 1
            retCode = lastIndex.ToString("D" & sysCurrentLedgerSetting.LedgerSubAcctLength)
            Return lastAcctCls.AccountCode & retCode
        End If



        lastAcctCls = TryCast(node.Nodes(lastIndex).Tag, ClsTAccount)

        lastCode = IIf(lastAcctCls Is Nothing, Nothing, lastAcctCls.AccountCode)

        Dim tmpNumStr As String
        If lastCode.Length <= 3 Then
            tmpNumStr = lastCode
        Else
            tmpNumStr = lastCode.Substring(lastCode.Length - 3, 3)
        End If

        retCode = IIf(lastCode Is Nothing, Nothing, lastCode.Substring(0, lastCode.Length - 3) & （Integer.Parse(tmpNumStr) + 1).ToString("D3"))

        Return retCode
    End Function

    Private Sub btnAddNext_Click(sender As Object, e As EventArgs) Handles btnAddNext.Click
        '判断当下是否可以新增
        If m_curAcctCls Is Nothing Then
            MessageBox.Show("请先选择一个科目，不能选择科目组（如资产）。", "新增下级科目")
            Return
        End If

        '判断当前选中科目是否为明细科目
        If m_curAcctCls.IfLastLevel Then
            MessageBox.Show("当前选择科目是一个明细科目，不能增加下级科目，如要操作，请先修改当前科目为非下级科目。", "新增下级科目")
            Return
        End If

        '修改状态
        m_state = 1 '新增
        '修改取消按钮文字
        Me.btnCancel.Text = "取消新增下级&U"

        '锁定树控件
        Me.treeAcct.Enabled = False

        '检查当前控件状态
        CheckControlState()

        '填写必要的值 
        Dim tmpCode As String = GetNewNextAcctCode(m_curNode)
        Me.txtAcctCode.Text = IIf(tmpCode Is Nothing, "无法创建下级科目", tmpCode)
        Me.txtAcctName.Text = ""
        Me.txtPrevLevelCode.Text = m_curAcctCls.AccountCode
        Me.txtLevel.Text = m_curAcctCls.Level + 1
        Me.txtFullName.Text = ""
        Me.txtShortName.Text = ""
    End Sub

    Private Sub btnCancel_Click(sender As Object, e As EventArgs) Handles btnCancel.Click
        If m_state = 0 Then
            Return
        End If

        If MessageBox.Show("确定取消当前的编辑工作？", "取消编辑", MessageBoxButtons.YesNo) = DialogResult.No Then
            Return
        End If

        '恢复浏览状态
        m_state = 0
        m_saving = False
        m_dirty = False
        '恢复树控件
        Me.treeAcct.Enabled = True
        '恢复当前操作对象
        ClassToControl()

        '检查控件状态
        CheckControlState()

    End Sub

    Private Sub btnSave_Click(sender As Object, e As EventArgs) Handles btnSave.Click
        '保存
        If Not m_dirty And m_state = 2 Then
            '修改但并未有任何值改变
            '直接关闭修改状态
            m_state = 0
            Me.treeAcct.Enabled = True
            CheckControlState()
            Return
        End If

        '进行保存
        WriteToDb()
    End Sub

    ''' <summary>
    ''' 保存编辑结果到数据库中
    ''' </summary>
    Private Sub WriteToDb()
        '判断是否可以保存
        If Not ValidateControlContent() Then
            Return
        End If
        '1、控件内容入对象
        Me.txtShortName.Text = GetPinYinCaptial(Me.txtAcctName.Text)
        '保存到对象中，准备保存
        ControlToClass()

        '3、解锁树控件
        Me.treeAcct.Enabled = True

        '4、禁止所有按钮
        Me.btnAddNext.Enabled = False
        Me.btnModify.Enabled = False
        Me.btnAddSame.Enabled = False
        Me.btnCancel.Enabled = False
        Me.btnInput.Enabled = False
        Me.btnSave.Enabled = False
        Me.btnClose.Enabled = False
        '5、开始保存
        Dim tmpAcctDb As ClsTAccountDbAccess = New ClsTAccountDbAccess(sysUserDataConnectionString)
        Dim tmpResult As Integer '保存结果
        If m_state = 1 Then
            tmpResult = tmpAcctDb.InsertAccount(m_curAcctCls)
        Else
            tmpResult = tmpAcctDb.UpdateAccount(m_curAcctCls)
            '如果修改的科目已被使用，则需要修改使用的名称
            Dim tmpClsVDDb As ClsTVoucherDetailDbAccess = New ClsTVoucherDetailDbAccess(sysUserDataConnectionString)
            If tmpClsVDDb.UpdateAcctInEntry(m_curAcctCls, m_curAcctCls.AccountCode) Then
                '如果修改分录科目信息出错
            End If
        End If

        '6、保存成功
        If tmpResult <> 0 Then
            Dim tmpNode As TreeNode '= New TreeNode()
            '通知订阅方
            Dim e As TransEventArg = New TransEventArg()
            If m_state = 1 Then
                '如果是新建则添加到集合中
                m_acctList.Add(m_curAcctCls)
                '如果是新建则添加到树中
                tmpNode = New TreeNode()
                tmpNode.Name = m_curAcctCls.AccountCode
                tmpNode.Text = m_curAcctCls.AccountCode & " - " & m_curAcctCls.AccountName
                tmpNode.Tag = m_curAcctCls

                '判断当前添加位置
                If m_curAcctCls.Level = 1 Then
                    '添加到组中
                    Me.treeAcct.Nodes(m_curAcctCls.AccountType).Nodes.Add(tmpNode)
                Else
                    '添加到父下
                    Dim parentNode As TreeNode = m_curNode.Parent
                    Dim templateAcct As ClsTAccount = TryCast(m_curNode.Tag, ClsTAccount)
                    If templateAcct.Level = m_curAcctCls.Level Then
                        '增加同级
                        parentNode.Nodes.Add(tmpNode)
                    Else
                        '增加下级
                        m_curNode.Nodes.Add(tmpNode)
                    End If
                    'Me.treeAcct.Nodes(m_curAcctCls.PrevLevelCode).Nodes.Add(tmpNode)
                End If

                '保存完毕，通知订阅方
                e.Msg = "InsertAccount"
                e.Obj = m_curAcctCls


            Else
                '如果是修改则修改树中内容
                '取出当前所在节点
                m_curNode.Text = m_curAcctCls.AccountCode & " - " & m_curAcctCls.AccountName
                '修改成功，通知订阅方
                e.Msg = "ModifyAccount"
                e.Obj = m_curAcctCls

            End If

            '发布事件，通知订阅方
            m_broker.BroadCastEvent(e)

        End If
        '2、修改当前状态值 
        m_saving = True
        m_dirty = False
        m_state = 0
        m_canEdit = True
        m_saving = False
        '7、检查控件状态
        CheckControlState()

    End Sub

    ''' <summary>
    ''' 检查当前控件的内容是否符合科目要求
    ''' </summary>
    ''' <returns>True符合</returns>
    Private Function ValidateControlContent() As Boolean


        Dim tmpCode As String = Me.txtAcctCode.Text.Trim
        If String.IsNullOrEmpty(tmpCode) Then
            MessageBox.Show("科目编号不能为空！", "科目保存")
            Return False
        End If

        If m_state = 1 AndAlso ExistAcctCode(tmpCode) Then
            MessageBox.Show("新增科目编号已经存在，请修改后再保存！", "科目保存")
            Return False
        End If

        Dim tmpLevel As Integer = Integer.Parse(Me.txtLevel.Text)
        If tmpLevel = 1 AndAlso tmpCode.Length <> sysCurrentLedgerSetting.OneAcctLevelLength Then
            MessageBox.Show("一级科目编码长度不正确，必须为" & sysCurrentLedgerSetting.OneAcctLevelLength & "位。请修改后再保存！", "科目保存")
            Return False
        End If

        Dim tmpIfLastLevel As Boolean = Me.chkIfLastLevel.Checked

        If tmpLevel > 1 AndAlso Not tmpIfLastLevel Then
            If MessageBox.Show("编辑的科目不是明细科目，非明细科目是不能在凭证中使用的，请问是否需要修改？", "科目保存", MessageBoxButtons.YesNo) = DialogResult.Yes Then
                Return False
            End If
        End If

        Dim tmpName As String = Me.txtAcctName.Text.Trim
        If String.IsNullOrEmpty(tmpName) Then
            MessageBox.Show("科目名称不能为空！", "科目保存")
            Return False
        End If

        Dim tmpType As String = Me.cmbAcctType.SelectedValue
        If m_curAcctCls IsNot Nothing AndAlso Not tmpType.Equals(m_curAcctCls.AccountType) Then
            If MessageBox.Show("编辑的科目 类型 和所选科目模板不匹配(科目模板是" & m_curAcctCls.AccountType & "类科目)，是否需要修改？", "科目保存", MessageBoxButtons.YesNo) = DialogResult.Yes Then
                Return False
            End If
        End If

        Dim tmpIfQuantity As Boolean = Me.chkIfQuantity.Checked
        Dim tmpUnit As String = Me.txtQuantityUnit.Text.Trim()
        If tmpIfQuantity AndAlso String.IsNullOrEmpty(tmpUnit) Then
            If MessageBox.Show("编辑的科目勾选了数量核算，但并未填写数量单位。请问是否需要填写？", "科目保存", MessageBoxButtons.YesNo) = DialogResult.Yes Then
                Return False
            End If
        End If

        Dim tmpTransit As String = Me.cmbTransit.SelectedValue
        Dim tmpTransitCode As String = Me.txtTransitAcctCode.Text.Trim()

        If Not String.IsNullOrEmpty(tmpTransit) AndAlso String.IsNullOrEmpty(tmpTransitCode) Then
            If MessageBox.Show("编辑的科目选择了月末结转方式，但并未填写结转的对方科目。请问是否需要填写？", "科目保存", MessageBoxButtons.YesNo) = DialogResult.Yes Then
                Return False
            End If
        End If

        Return True
    End Function

    Private Function ExistAcctCode(ByVal c As String) As Boolean
        For Each tmpA As ClsTAccount In m_acctList
            If tmpA.AccountCode.Equals(c) Then
                Return True
            End If
        Next

        Return False
    End Function

    Private Sub chkIfLastLevel_CheckedChanged(sender As Object, e As EventArgs) Handles chkIfLastLevel.CheckedChanged
        '如果当前是编辑状态，则需要判断当前科目是否是 明细 改非明细，如果是，则需要判断当前科目是否已经在凭证中使用了。
        '如果已经在凭证中使用，则需要提醒用户，这样做是风险的。如果要修改，则把当前的科目修改为明细科目，并自动生成一个下级科目。
        '并将凭证中已经使用的该科目修改为新生成的下级科目。并将新下级科目变成当前编辑科目。让用户修改。
        If m_state <> 2 Then
            Return
        End If

        '判断当前状态是否和当前对象状态一致，
        If Me.chkIfLastLevel.Checked Then
            '勾选
            '判断当前科目是否有下级
            '根据当前科目编号取出树节点对象
            'TODO:遍历选择树对象
            Dim tmpN As TreeNode = GetNodeByName(m_curAcctCls.AccountCode, m_curAcctCls.AccountType)
            If tmpN.Nodes.Count > 0 Then
                '当前选择的科目有下级科目，则不能修改为明细科目
                MessageBox.Show("当前科目有下级科目，不能修改为明细科目。", "科目编辑")
                Me.chkIfLastLevel.Checked = False
                Return
            End If
            '没有下级
        End If

        If Not Me.chkIfLastLevel.Checked Then
            '没勾选
            Dim tmpVoucherDetailDb As ClsTVoucherDetailDbAccess = New ClsTVoucherDetailDbAccess(sysUserDataConnectionString)
            If tmpVoucherDetailDb.AcctExistInVoucher(Me.txtAcctCode.Text.Trim()) Then
                '提醒
                If MessageBox.Show("当前科目已在凭证中使用，请问是否继续修改为非末级科目？", "科目修改", MessageBoxButtons.YesNo) = DialogResult.No Then
                    Me.chkIfLastLevel.Checked = True
                    Return
                End If
                '这里要把当前科目变成非末级科目，并自动生成一个新的下级科目，并把新的下级科目变成当下编辑的科目。
                '第一步，把当前修改科目存盘
                '保存年初数
                Dim tmpAcctYearMoney As Decimal = m_curAcctCls.YearMoney
                Dim tmpAcctYearCurrency As Decimal = m_curAcctCls.YearCurrency
                Dim tmpAcctYearQuantity As Single = m_curAcctCls.YearQuantity
                '1\修改当前科目
                m_curAcctCls.IfLastLevel = False
                m_curAcctCls.YearMoney = 0
                m_curAcctCls.YearCurrency = 0
                m_curAcctCls.YearQuantity = 0
                Dim tmpAcctDb As ClsTAccountDbAccess = New ClsTAccountDbAccess(sysUserDataConnectionString)
                '2、保存修改
                If tmpAcctDb.UpdateAccount(m_curAcctCls) = 0 Then
                    '出错
                    MessageBox.Show("保存当前编辑结果时出错。", "保存科目")
                    Return
                End If

                '第二步，生成一个新的下级科目，科目名称叫 承接上级科目余额
                '1、生成一个新的下级科目
                Dim tmpNewNextLevelAcctCode As String = GetNewNextAcctCode(m_curNode)
                Dim tmpNewNextAcctCls As ClsTAccount = New ClsTAccount()
                '2、复制科目基本内容
                With tmpNewNextAcctCls
                    .AccountCode = tmpNewNextLevelAcctCode
                    .PrevLevelCode = m_curAcctCls.AccountCode
                    .Level = m_curAcctCls.Level + 1
                    .AccountName = "承接余额（需要修改）"
                    .ShortName = ""
                    .FullName = "承接余额（需要修改）"
                    .IfLastLevel = True
                    .AccountType = m_curAcctCls.AccountType
                    .YearMoney = tmpAcctYearMoney '把上级科目年初数移到新的下级科目来
                    .BalanceDirection = m_curAcctCls.BalanceDirection
                    .YearCurrency = tmpAcctYearCurrency
                    .CurrencyCode = m_curAcctCls.CurrencyCode
                    .IfRateAdjust = m_curAcctCls.IfRateAdjust
                    .IfQuantity = m_curAcctCls.IfQuantity
                    .QuantityUnit = m_curAcctCls.QuantityUnit
                    .YearQuantity = tmpAcctYearQuantity
                    .IfProject = m_curAcctCls.IfProject
                    .IfCustomer = m_curAcctCls.IfCustomer
                    .IfDepartment = m_curAcctCls.IfDepartment
                    .IfEmployee = m_curAcctCls.IfEmployee
                    .MonthTransit = m_curAcctCls.MonthTransit
                    .MonthTransitAcctCode = m_curAcctCls.MonthTransitAcctCode
                    .AbSet = m_curAcctCls.AbSet

                End With
                '3、保存新的科目
                If tmpAcctDb.InsertAccount(tmpNewNextAcctCls) = 0 Then
                    '出错
                    MessageBox.Show("保存承接余额的新科目时出错。", "保存科目")
                    Return
                End If
                '4、把凭证中的相应科目修改为当前保存的新下级科目
                If tmpVoucherDetailDb.UpdateAcctInEntry(tmpNewNextAcctCls, m_curAcctCls.AccountCode) = 0 Then
                    '出错
                    MessageBox.Show("更新原凭证中的科目时出错，请手工修改这些凭证。", "保存科目")
                    Return
                End If
                '第三步，把新的科目添加到科目列表中

                '取出当前科目的索引
                Dim tmpIndex As Integer = m_acctList.IndexOf(m_curAcctCls)
                '将新科目插入到当前科目下
                m_acctList.Insert(tmpIndex, tmpNewNextAcctCls)
                '第四步，把新的科目变成当前编辑科目
                m_curAcctCls = tmpNewNextAcctCls
                '第五步，把新的科目添加到树控件中
                Dim tmpNode As TreeNode '= New TreeNode()
                '通知订阅方
                Dim e1 As TransEventArg = New TransEventArg()
                '如果是新建则添加到树中
                tmpNode = New TreeNode()
                tmpNode.Name = m_curAcctCls.AccountCode
                tmpNode.Text = m_curAcctCls.AccountCode & " - " & m_curAcctCls.AccountName
                tmpNode.Tag = m_curAcctCls

                '判断当前添加位置
                If m_curAcctCls.Level = 1 Then
                    '添加到组中
                    Me.treeAcct.Nodes(m_curAcctCls.AccountType).Nodes.Add(tmpNode)
                Else
                    '添加到父下
                    Dim parentNode As TreeNode = m_curNode.Parent
                    Dim templateAcct As ClsTAccount = TryCast(m_curNode.Tag, ClsTAccount)
                    If templateAcct.Level = m_curAcctCls.Level Then
                        '增加同级
                        parentNode.Nodes.Add(tmpNode)
                    Else
                        '增加下级
                        m_curNode.Nodes.Add(tmpNode)
                    End If
                    'Me.treeAcct.Nodes(m_curAcctCls.PrevLevelCode).Nodes.Add(tmpNode)
                End If

                '保存完毕，通知订阅方
                e1.Msg = "InsertAccount"
                e1.Obj = m_curAcctCls
                '发布事件，通知订阅方
                m_broker.BroadCastEvent(e1)

                '修改编辑状态
                m_state = 0
                m_dirty = False
                m_saving = False
                '
                ClassToControl()
                '
                CheckControlState()
            End If
        End If

        m_dirty = True
        Me.btnSave.Enabled = True
    End Sub



    Private Sub btnModify_Click(sender As Object, e As EventArgs) Handles btnModify.Click
        '修改科目
        If m_curAcctCls Is Nothing Then
            Return
        End If

        Me.btnCancel.Text = "取消科目编辑&U"

        Me.treeAcct.Enabled = False

        m_state = 2
        m_dirty = False
        m_canEdit = False
        m_saving = False

        CheckControlState()

    End Sub


    Private Sub cmbAcctType_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbAcctType.SelectedIndexChanged
        m_dirty = True
        Me.btnSave.Enabled = True
    End Sub


    Private Sub cmbBalanceDirection_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbBalanceDirection.SelectedIndexChanged
        m_dirty = True
        Me.btnSave.Enabled = True
    End Sub


    Private Sub chkIfProject_CheckedChanged(sender As Object, e As EventArgs) Handles _
            chkIfProject.CheckedChanged, chkIfAdjust.CheckedChanged,
            chkIfQuantity.CheckedChanged, chkIfCustomer.CheckedChanged,
            chkIfDepartment.CheckedChanged, chkIfEmployee.CheckedChanged


        m_dirty = True
        Me.btnSave.Enabled = True
    End Sub

    Private Sub cmbTransit_SelectedIndexChanged(sender As Object, e As EventArgs) Handles cmbTransit.SelectedIndexChanged
        m_dirty = True
        Me.btnSave.Enabled = True

    End Sub

    Private Sub btnDelete_Click(sender As Object, e As EventArgs) Handles btnDelete.Click
        '删除当前选中科目
        If m_curAcctCls Is Nothing Then
            MessageBox.Show("请先选择一个待删除科目", "删除科目")
            Return
        End If

        '第一步，判断是否有下级科目
        If m_curNode.Nodes.Count > 0 Then
            '当前科目有下级科目，不能删除
            MessageBox.Show("当前科目有下级科目不能删除。如果要删除，请先删除下级科目。", "删除科目")
            Return
        End If
        '第二步，没有下级，判断是否为一级科目，如果是则提醒
        If m_curAcctCls.Level = 1 Then
            If MessageBox.Show("当前科目是一级科目，真的要删除吗？", "删除科目", MessageBoxButtons.YesNo) = DialogResult.No Then
                Return
            End If
        End If
        '第三步，判断当前科目是否已经使用，如果已经使用，不能删除
        Dim tmpVoucherDb As ClsTVoucherDetailDbAccess = New ClsTVoucherDetailDbAccess(sysUserDataConnectionString)
        If tmpVoucherDb.AcctExistInVoucher(m_curAcctCls.AccountCode) Then
            MessageBox.Show("当前科目已经被使用，不能删除。如果要删除，请先删除使用该科目的凭证。", "删除科目")
            Return
        End If
        '第四步，可以删除
        Dim tmpAcctDb As ClsTAccountDbAccess = New ClsTAccountDbAccess(sysUserDataConnectionString)
        If tmpAcctDb.DeleteAccount(m_curAcctCls) > 0 Then
            '成功
            '从集合中删除
            m_acctList.Remove(m_curAcctCls)
            '通知订阅对象
            Dim tmpArg As TransEventArg = New TransEventArg()
            tmpArg.Msg = "DeleteAccount"
            tmpArg.Obj = m_curAcctCls
            m_broker.BroadCastEvent(tmpArg)

            '从树中删除
            m_curNode.Remove()

            '修改当前对象
            m_curAcctCls = Nothing
            m_curNode = Nothing
        Else
            '失败
            '暂时似乎没什么需要做的
        End If
    End Sub
End Class